package com.example.utils;

import com.example.entity.ResultData;
import com.example.entity.ReturnCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.codec.DecodingException;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import reactor.core.publisher.Mono;

import javax.validation.ConstraintViolationException;

/**
 * @author: Cherry
 * @create: 2021-09-15 10:25
 * @description: 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {

    /**
     * 在返回异常的同时，收集数据并记录日志
     * @param exception exception
     * @return exception
     */
    protected void logRichInfoError(Exception exception){
        // 获取reactor上下文
        log.error("全局异常信息 : ex={}", exception.getMessage(), exception);
    }

    /** 拦截逻辑通用异常*/
    @ExceptionHandler({RuntimeException.class})
    public Object bodyDefaultExceptionHandler(Exception exception, ServerHttpResponse response) {
        logRichInfoError(exception);
        // 从异常中获取错误代码
        Integer errorCode = ReturnCode.RC500.getCode();
        if (exception instanceof ResponseStatusException) {
            ResponseStatusException resEx = (ResponseStatusException) exception;
            HttpStatus status = resEx.getStatus();
            response.setStatusCode(status);
            errorCode = status.value();
        }
        return ResultData.fail(errorCode, exception.getMessage());
    }


    /** 拦截业务异常, 就为了这个200状态码*/
    @ExceptionHandler(TypicalRepException.class)
    @ResponseStatus(HttpStatus.OK)
    public Object typicalExceptionHandler(Exception exception) {
        logRichInfoError(exception);
        TypicalRepException re = (TypicalRepException) exception;
        Integer code = re.getCode();
        String msg = re.getMessage();
        Object data = re.getData();

        return ResultData.fail(code, msg, data);
    }

    /** json参数解析异常*/
    @ExceptionHandler({com.fasterxml.jackson.databind.exc.InvalidDefinitionException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object jsonExceptionHandler(Exception exception) {
        logRichInfoError(exception);
        return ResultData.fail(ReturnCode.RC601.getCode(), ReturnCode.RC601.getMessage());
    }

    /** 表单验证异常*/
    @ExceptionHandler({MethodArgumentNotValidException.class, ConstraintViolationException.class , BindException.class, WebExchangeBindException.class, IllegalArgumentException.class, DecodingException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object bodyValidExceptionHandler(Exception exception) {
        logRichInfoError(exception);
        if (exception instanceof WebExchangeBindException && "Validation failure".equals(((WebExchangeBindException) exception).getReason())){
            String defaultMessage = ((WebExchangeBindException) exception).getBindingResult().getFieldError().getDefaultMessage();
            return ResultData.fail(ReturnCode.RC601.getCode(), defaultMessage);
        }
        return ResultData.fail(ReturnCode.RC601.getCode(), "表单验证失败:" + exception.getMessage());
    }

    /**400请求错误*/
    @ExceptionHandler({ServerWebInputException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object webInputExceptionHandler(ServerWebInputException exception) {
        logRichInfoError(exception);
        return ResultData.fail(exception.getStatus().value(), "请求错误:" + exception.getMessage());
    }

    /**415请求错误*/
    @ExceptionHandler({UnsupportedMediaTypeStatusException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object UnsupportedMediaTypeExceptionHandler(UnsupportedMediaTypeStatusException exception) {
        logRichInfoError(exception);
        return ResultData.fail(exception.getStatus().value(), "请求错误:" + exception.getMessage());
    }



    /*@ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object exception(Exception exception) {
        logRichInfoError(exception);

        if (exception instanceof TypicalRepException){
            TypicalRepException e = (TypicalRepException) exception;
            Integer code = e.getCode();
            String message = e.getMessage();
            Object data = e.getData();

            code = java.util.Objects.isNull(code) ? ReturnCode.RC500.getCode() : code;
            message = java.util.Objects.isNull(message) ? "" : message;

            return new ResultData<>(code,message,data);
        }
        return defaultExceptionHandler(exception);

    }

    *//**
     * 默认异常
     * @param exception
     * @return
     *//*
    protected ResultData defaultExceptionHandler(Exception exception){
        return new ResultData<>(ReturnCode.RC500.getCode(), "当前网络不可用，请稍后再试", "");
    }*/
}
